VersionSelector.render   C
last analyzed

Complexity

Conditions 7

Size

Total Lines 107
Code Lines 92

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 92
dl 0
loc 107
rs 5.8618
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import ReactDOM from 'react-dom';
4
5
import {
6
  Row,
7
  Col,
8
  FormControl,
9
  ButtonToolbar,
10
  ButtonGroup,
11
  Button,
12
  OverlayTrigger,
13
  Tooltip,
14
} from 'react-bootstrap';
15
16
const defaultCondition = { comparator: '*' };
17
const defaultConditionAdded = { comparator: '~' };
18
19
export default class VersionSelector extends React.Component {
20
  constructor(props) {
21
    super(props);
22
    this.state = {
23
      values: [defaultCondition],
24
      addButtonDisabled: false,
25
    };
26
    this.focusInputs = {};
27
  }
28
29
  componentWillReceiveProps(newProps) {
30
    if (newProps.values) {
31
      this.setState({
32
        values: newProps.values,
33
        addButtonDisabled: newProps.values.some(val => val.comparator === '*'),
34
      });
35
    }
36
  }
37
38
  onVersionChanged(index, changedItem) {
39
    const newValues = this.state.values.slice();
40
    newValues[index] = Object.assign({}, this.state.values[index], changedItem);
41
    this.setState({
42
      values: newValues,
43
      addButtonDisabled: newValues.some(val => val.comparator === '*'),
44
    }, () => {
45
      if (changedItem.comparator && this.focusInputs[index][changedItem.comparator]) {
46
        ReactDOM.findDOMNode(this.focusInputs[index][changedItem.comparator]).focus();
47
      }
48
      this.onChanged();
49
    });
50
  }
51
52
  onChanged() {
53
    if (typeof this.props.onChange === 'function') {
54
      this.props.onChange(this.state.values);
55
    }
56
  }
57
58
  addCondition() {
59
    const newValues = this.state.values.slice();
60
    newValues.push(defaultConditionAdded);
61
    this.setState({ values: newValues }, () => this.onChanged());
62
  }
63
64
  removeCondition(idx) {
65
    const newValues = this.state.values.slice();
66
    newValues.splice(idx, 1);
67
    this.setState({ values: newValues }, () => this.onChanged());
68
  }
69
70
  render() {
71
    const values = this.state.values || [defaultCondition];  // default
72
    return (
73
      <div className="version-selector-container">
74
        {values.map((value, index) => {
75
          return (
76
            <div className="selector-item" key={index}>
77
              <ButtonToolbar className="selector-comparator">
78
                <ButtonGroup>
79
                  <OverlayTrigger placement="top" overlay={<Tooltip>모든 범위</Tooltip>}>
80
                    <Button
81
                      active={value.comparator === '*'}
82
                      onClick={() => this.onVersionChanged(index, { comparator: '*' })}
83
                      disabled={this.props.disabled}
84
                    >
85
                      &#x2731; {/* asterisk */}
86
                    </Button>
87
                  </OverlayTrigger>
88
                  <OverlayTrigger placement="top" overlay={<Tooltip>범위 지정</Tooltip>}>
89
                    <Button
90
                      active={value.comparator === '~'}
91
                      onClick={() => this.onVersionChanged(index, { comparator: '~' })}
92
                      disabled={this.props.disabled}
93
                    >
94
                      &#x0223C; {/* tilda */}
95
                    </Button>
96
                  </OverlayTrigger>
97
                  <OverlayTrigger placement="top" overlay={<Tooltip>일치</Tooltip>}>
98
                    <Button
99
                      active={value.comparator === '='}
100
                      onClick={() => this.onVersionChanged(index, { comparator: '=' })}
101
                      disabled={this.props.disabled} style={{ paddingTop: '5px', paddingBottom: '7px' }}
102
                    >
103
                      =
104
                    </Button>
105
                  </OverlayTrigger>
106
                </ButtonGroup>
107
              </ButtonToolbar>
108
              <FormControl
109
                className="selector-inputs"
110
                type="text"
111
                value={'모든 버전 대상'}
112
                style={value.comparator !== '*' ? { display: 'none' } : {}}
113
                readOnly
114
              />
115
              <FormControl
116
                ref={(f) => {
117
                  if (!this.focusInputs[index]) {
118
                    this.focusInputs[index] = {};
119
                  }
120
                  this.focusInputs[index]['~'] = f;
121
                }}
122
                className="selector-inputs"
123
                type="text"
124
                value={value.versionStart}
125
                onChange={e => this.onVersionChanged(index, { versionStart: e.target.value })}
126
                placeholder=">= 시작 버전 (X.Y.Z 형태)"
127
                disabled={this.props.disabled}
128
                style={value.comparator !== '~' ? { display: 'none' } : {}}
129
              />
130
              <FormControl
131
                className="selector-inputs selector-inputs-second"
132
                type="text"
133
                value={value.versionEnd}
134
                onChange={e => this.onVersionChanged(index, { versionEnd: e.target.value })}
135
                placeholder="< 끝 버전 (X.Y.Z 형태)"
136
                disabled={this.props.disabled}
137
                style={value.comparator !== '~' ? { display: 'none' } : {}}
138
              />
139
              <FormControl
140
                ref={(f) => {
141
                  if (!this.focusInputs[index]) {
142
                    this.focusInputs[index] = {};
143
                  }
144
                  this.focusInputs[index]['='] = f;
145
                }}
146
                className="selector-inputs"
147
                type="text"
148
                value={value.version}
149
                onChange={e => this.onVersionChanged(index, { version: e.target.value })}
150
                placeholder="= 일치하는 버전 (X.Y.Z 형태)"
151
                style={value.comparator !== '=' ? { display: 'none' } : {}}
152
                disabled={this.props.disabled}
153
              />
154
              <Button
155
                className="selector-remove-btn"
156
                onClick={() => this.removeCondition(index)}
157
                disabled={index === 0 || this.props.disabled}
158
              >
159
                &#x2715;
160
              </Button>
161
            </div>
162
          );
163
        })}
164
        <Row>
165
          <Col xs={12}>
166
            <Button
167
              className="selector-add-btn"
168
              onClick={() => this.addCondition()}
169
              disabled={this.props.disabled || this.state.addButtonDisabled}
170
            >
171
              + 조건 추가 (OR)
172
            </Button>
173
          </Col>
174
        </Row>
175
      </div>
176
    );
177
  }
178
}
179
180
VersionSelector.propTypes = {
181
  values: PropTypes.arrayOf(PropTypes.shape({
182
    comparator: PropTypes.string.isRequired,
183
    versionStart: PropTypes.string,
184
    versionEnd: PropTypes.string,
185
    version: PropTypes.string,
186
  })),
187
  onChange: PropTypes.func,
188
  disabled: PropTypes.bool,
189
};
190